package app.modules.infrastructure.lov.business.service;

import app.modules.common.constant.TenantConstants;
import app.modules.common.enums.EnableFlagEnum;
import app.modules.common.exception.UnauthorizedDataAccessException;
import app.modules.infrastructure.lov.constant.LovConstants;
import app.modules.infrastructure.lov.constant.LovMsgConstants;
import app.modules.infrastructure.lov.dto.web.WebValueSetDTO;
import app.modules.infrastructure.lov.dto.web.WebValueSetQueryDTO;
import app.modules.infrastructure.lov.dto.web.WebValueSetSaveDTO;
import app.modules.infrastructure.lov.dto.web.WebValueSetUpdateDTO;
import app.modules.infrastructure.lov.persistence.dao.ValueSetDAO;
import app.modules.infrastructure.lov.persistence.entity.ValueSetEO;
import app.modules.infrastructure.lov.util.conversion.ValueSetConvertUtil;
import com.baomidou.mybatisplus.extension.plugins.pagination.Page;
import jasmine.framework.common.exception.BusinessException;
import jasmine.framework.common.exception.DataNotFoundException;
import jasmine.framework.common.util.CheckUtil;
import jasmine.framework.common.util.CollectionUtil;
import jasmine.framework.common.util.I18nUtil;
import jasmine.framework.common.util.MapperUtil;
import jasmine.framework.common.util.NewUtil;
import jasmine.framework.common.util.ObjectUtil;
import jasmine.framework.context.CurrentSubject;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;

import java.util.Collections;
import java.util.List;

/**
 * @author mh.z
 */
@Service
public class ValueSetService implements IValueSetService {
    private ValueSetDAO valueSetDAO;

    public ValueSetService(ValueSetDAO valueSetDAO) {
        this.valueSetDAO = valueSetDAO;
    }

    /**
     * 分页查询值集
     *
     * @param queryDTO
     * @param page
     * @return
     */
    public List<WebValueSetDTO> pageWebValueSetDTOsByCond(WebValueSetQueryDTO queryDTO, Page page) {
        CheckUtil.notNull(queryDTO, "queryDTO null");
        CheckUtil.notNull(page, "page null");

        List<WebValueSetDTO> recordList = valueSetDAO.pageWebValueSetDTOsByCond(queryDTO, page);
        populateWebValueSetDTO(recordList);

        return recordList;
    }

    /**
     * 填充数据
     *
     * @param records
     */
    protected void populateWebValueSetDTO(List<WebValueSetDTO> records) {
        if (CollectionUtil.isEmpty(records)) {
            return;
        }

        records.forEach((record) -> {
            EnableFlagEnum enableFlagEnum = EnableFlagEnum.parseValue(record.getEnableFlag());
            record.setEnableFlagDesc(I18nUtil.getMessage(enableFlagEnum));
        });
    }

    /**
     * 查找指定 ID 的记录
     *
     * @param id
     * @return
     */
    public WebValueSetDTO getWebValueSetDtoById(Long id) {
        CheckUtil.notNull(id, "id null");

        ValueSetEO valueSetEO = valueSetDAO.getById(id);
        WebValueSetDTO webValueSetDTO = ValueSetConvertUtil.valueSetEO2WebValueSetDTO(valueSetEO);
        populateWebValueSetDTO(Collections.singletonList(webValueSetDTO));

        return webValueSetDTO;
    }

    /**
     * 保存记录
     *
     * @param saveDTO
     * @return
     */
    @Transactional(rollbackFor = Exception.class)
    public WebValueSetDTO saveValueSet(WebValueSetSaveDTO saveDTO) {
        CheckUtil.notNull(saveDTO, "saveDTO null");

        String valueSetCode = saveDTO.getValueSetCode();
        long valueSetCodeCount = valueSetDAO.countByValueSetCode(valueSetCode, null);

        if (valueSetCodeCount > 0) {
            throw new BusinessException(LovMsgConstants.THE_VALUE_SET_CODE_ALREADY_EXISTS,
                    NewUtil.array(valueSetCode));
        }

        ValueSetEO valueSetEO = new ValueSetEO();
        MapperUtil.mapFields(saveDTO, valueSetEO);
        // 设置全局代码
        Long tenantId = CurrentSubject.getTenantId();
        String valueSetGlobalCode = getValueSetGlobalCode(tenantId, valueSetCode);
        valueSetEO.setValueSetGlobalCode(valueSetGlobalCode);
        // 设置租户ID
        valueSetEO.setTenantId(tenantId);
        // 保存记录
        valueSetDAO.save(valueSetEO);

        return getWebValueSetDtoById(valueSetEO.getId());
    }

    /**
     * 更新记录
     *
     * @param updateDTO
     * @return
     */
    @Transactional(rollbackFor = Exception.class)
    public WebValueSetDTO updateValueSet(WebValueSetUpdateDTO updateDTO) {
        CheckUtil.notNull(updateDTO, "updateDTO null");
        Long id = CheckUtil.notNull(updateDTO.getId(), "updateDTO.id null");

        String valueSetCode = updateDTO.getValueSetCode();
        long valueSetCodeCount = valueSetDAO.countByValueSetCode(valueSetCode,
                Collections.singletonList(id));

        if (valueSetCodeCount > 0) {
            throw new BusinessException(LovMsgConstants.THE_VALUE_SET_CODE_ALREADY_EXISTS,
                    NewUtil.array(valueSetCode));
        }

        ValueSetEO valueSetEO = valueSetDAO.getById(id);
        if (valueSetEO == null) {
            throw new DataNotFoundException(ValueSetEO.class, id);
        }

        if (ObjectUtil.notEqual(valueSetEO.getTenantId(), CurrentSubject.getTenantId())) {
            throw new UnauthorizedDataAccessException()
                    .withErrorDetail(ValueSetEO.class, id, null);
        }

        MapperUtil.mapFields(updateDTO, valueSetEO);
        // 设置全局代码
        String valueSetGlobalCode = getValueSetGlobalCode(valueSetEO.getTenantId(), valueSetCode);
        valueSetEO.setValueSetGlobalCode(valueSetGlobalCode);
        // 更新记录
        valueSetDAO.strictUpdateById(valueSetEO);

        return getWebValueSetDtoById(id);
    }

    /**
     * 生成值集全局代码
     *
     * @param tenantId
     * @param valueSetCode
     * @return
     */
    protected String getValueSetGlobalCode(Long tenantId, String valueSetCode) {
        String valueSetGlobalCode;

        if (ObjectUtil.equal(tenantId, TenantConstants.SYSTEM_TENANT_ID)) {
            valueSetGlobalCode = LovConstants.VALUE_SET_GLOBAL_CODE_APP_PREFIX + valueSetCode;
        } else {
            valueSetGlobalCode = LovConstants.VALUE_SET_GLOBAL_CODE_TENANT_PREFIX + valueSetCode;
        }

        return valueSetGlobalCode;
    }

}
